<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>堆积木</title>
    <style>
        @import url("pile/index.css");

        html,
        body {
            margin: 0;
            overflow: hidden;
            height: 100%;
            width: 100%;
            position: relative;
            font-family: 'Comfortaa', cursive;
        }

        #container {
            width: 100%;
            height: 100%;
        }

        #container #score {
            position: absolute;
            top: 20px;
            width: 100%;
            text-align: center;
            font-size: 10vh;
            -webkit-transition: -webkit-transform 0.5s ease;
            transition: -webkit-transform 0.5s ease;
            transition: transform 0.5s ease;
            transition: transform 0.5s ease, -webkit-transform 0.5s ease;
            color: #333344;
            -webkit-transform: translatey(-200px) scale(1);
            transform: translatey(-200px) scale(1);
        }

        #container #game {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
        }

        #container .game-over {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 85%;
            display: -webkit-box;
            display: -ms-flexbox;
            display: flex;
            -webkit-box-orient: vertical;
            -webkit-box-direction: normal;
            -ms-flex-direction: column;
            flex-direction: column;
            -webkit-box-align: center;
            -ms-flex-align: center;
            align-items: center;
            -webkit-box-pack: center;
            -ms-flex-pack: center;
            justify-content: center;
        }

        #container .game-over * {
            -webkit-transition: opacity 0.5s ease, -webkit-transform 0.5s ease;
            transition: opacity 0.5s ease, -webkit-transform 0.5s ease;
            transition: opacity 0.5s ease, transform 0.5s ease;
            transition: opacity 0.5s ease, transform 0.5s ease, -webkit-transform 0.5s ease;
            opacity: 0;
            -webkit-transform: translatey(-50px);
            transform: translatey(-50px);
            color: #333344;
        }

        #container .game-over h2 {
            margin: 0;
            padding: 0;
            font-size: 40px;
        }

        #container .game-ready {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            display: -webkit-box;
            display: -ms-flexbox;
            display: flex;
            -webkit-box-orient: vertical;
            -webkit-box-direction: normal;
            -ms-flex-direction: column;
            flex-direction: column;
            -webkit-box-align: center;
            -ms-flex-align: center;
            align-items: center;
            -ms-flex-pack: distribute;
            justify-content: space-around;
        }

        #container .game-ready #start-button {
            -webkit-transition: opacity 0.5s ease, -webkit-transform 0.5s ease;
            transition: opacity 0.5s ease, -webkit-transform 0.5s ease;
            transition: opacity 0.5s ease, transform 0.5s ease;
            transition: opacity 0.5s ease, transform 0.5s ease, -webkit-transform 0.5s ease;
            opacity: 0;
            -webkit-transform: translatey(-50px);
            transform: translatey(-50px);
            border: 3px solid #333344;
            padding: 10px 20px;
            background-color: transparent;
            color: #333344;
            font-size: 30px;
        }

        #container #instructions {
            position: absolute;
            width: 100%;
            top: 16vh;
            left: 0;
            text-align: center;
            -webkit-transition: opacity 0.5s ease, -webkit-transform 0.5s ease;
            transition: opacity 0.5s ease, -webkit-transform 0.5s ease;
            transition: opacity 0.5s ease, transform 0.5s ease;
            transition: opacity 0.5s ease, transform 0.5s ease, -webkit-transform 0.5s ease;
            opacity: 0;
        }

        #container #instructions.hide {
            opacity: 0 !important;
        }

        #container.playing #score,
        #container.resetting #score {
            -webkit-transform: translatey(0px) scale(1);
            transform: translatey(0px) scale(1);
        }

        #container.playing #instructions {
            opacity: 1;
        }

        #container.ready .game-ready #start-button {
            opacity: 1;
            -webkit-transform: translatey(0);
            transform: translatey(0);
        }

        #container.ended #score {
            -webkit-transform: translatey(6vh) scale(1.5);
            transform: translatey(6vh) scale(1.5);
        }

        #container.ended .game-over * {
            opacity: 1;
            -webkit-transform: translatey(0);
            transform: translatey(0);
        }

        #container.ended .game-over p {
            -webkit-transition-delay: 0.3s;
            transition-delay: 0.3s;
        }
    </style>
</head>

<body>
    <meta name="viewport" content="width=device-width,user-scalable=no">

    <div id="container">
        <div id="game"></div>
        <div id="score">0</div>
        <div id="instructions">Click (or press the spacebar) to place the block</div>
        <div class="game-over">
            <h2>Game Over</h2>
            <p>You did great, you're the best.</p>
            <p>Click or spacebar to start again</p>
        </div>
        <div class="game-ready">
            <div id="start-button">Start</div>
            <div></div>
        </div>
    </div>

    <script src='pile/three.min.js'></script>
    <script src='pile/TweenMax.min.js'></script>

    <script>
        console.clear();
        var Stage = /** @class */ (function () {
            function Stage() {
                // container
                var _this = this;
                this.render = function () {
                    this.renderer.render(this.scene, this.camera);
                };
                this.add = function (elem) {
                    this.scene.add(elem);
                };
                this.remove = function (elem) {
                    this.scene.remove(elem);
                };
                this.container = document.getElementById('game');
                // renderer
                this.renderer = new THREE.WebGLRenderer({
                    antialias: true,
                    alpha: false
                });
                this.renderer.setSize(window.innerWidth, window.innerHeight);
                this.renderer.setClearColor('#D0CBC7', 1);
                this.container.appendChild(this.renderer.domElement);
                // scene
                this.scene = new THREE.Scene();
                // camera
                var aspect = window.innerWidth / window.innerHeight;
                var d = 20;
                this.camera = new THREE.OrthographicCamera(-d * aspect, d * aspect, d, -d, -100, 1000);
                this.camera.position.x = 2;
                this.camera.position.y = 2;
                this.camera.position.z = 2;
                this.camera.lookAt(new THREE.Vector3(0, 0, 0));
                //light
                this.light = new THREE.DirectionalLight(0xffffff, 0.5);
                this.light.position.set(0, 499, 0);
                this.scene.add(this.light);
                this.softLight = new THREE.AmbientLight(0xffffff, 0.4);
                this.scene.add(this.softLight);
                window.addEventListener('resize', function () {
                    return _this.onResize();
                });
                this.onResize();
            }
            Stage.prototype.setCamera = function (y, speed) {
                if (speed === void 0) {
                    speed = 0.3;
                }
                TweenLite.to(this.camera.position, speed, {
                    y: y + 4,
                    ease: Power1.easeInOut
                });
                TweenLite.to(this.camera.lookAt, speed, {
                    y: y,
                    ease: Power1.easeInOut
                });
            };
            Stage.prototype.onResize = function () {
                var viewSize = 30;
                this.renderer.setSize(window.innerWidth, window.innerHeight);
                this.camera.left = window.innerWidth / -viewSize;
                this.camera.right = window.innerWidth / viewSize;
                this.camera.top = window.innerHeight / viewSize;
                this.camera.bottom = window.innerHeight / -viewSize;
                this.camera.updateProjectionMatrix();
            };
            return Stage;
        }());
        var Block = /** @class */ (function () {
            function Block(block) {
                // set size and position
                this.STATES = {
                    ACTIVE: 'active',
                    STOPPED: 'stopped',
                    MISSED: 'missed'
                };
                this.MOVE_AMOUNT = 12;
                this.dimension = {
                    width: 0,
                    height: 0,
                    depth: 0
                };
                this.position = {
                    x: 0,
                    y: 0,
                    z: 0
                };
                this.targetBlock = block;
                this.index = (this.targetBlock ? this.targetBlock.index : 0) + 1;
                this.workingPlane = this.index % 2 ? 'x' : 'z';
                this.workingDimension = this.index % 2 ? 'width' : 'depth';
                // set the dimensions from the target block, or defaults.
                this.dimension.width = this.targetBlock ? this.targetBlock.dimension.width : 10;
                this.dimension.height = this.targetBlock ? this.targetBlock.dimension.height : 2;
                this.dimension.depth = this.targetBlock ? this.targetBlock.dimension.depth : 10;
                this.position.x = this.targetBlock ? this.targetBlock.position.x : 0;
                this.position.y = this.dimension.height * this.index;
                this.position.z = this.targetBlock ? this.targetBlock.position.z : 0;
                this.colorOffset = this.targetBlock ? this.targetBlock.colorOffset : Math.round(Math.random() *
                    100);
                // set color
                if (!this.targetBlock) {
                    this.color = 0x333344;
                } else {
                    var offset = this.index + this.colorOffset;
                    var r = Math.sin(0.3 * offset) * 55 + 200;
                    var g = Math.sin(0.3 * offset + 2) * 55 + 200;
                    var b = Math.sin(0.3 * offset + 4) * 55 + 200;
                    this.color = new THREE.Color(r / 255, g / 255, b / 255);
                }
                // state
                this.state = this.index > 1 ? this.STATES.ACTIVE : this.STATES.STOPPED;
                // set direction
                this.speed = -0.1 - (this.index * 0.005);
                if (this.speed < -4)
                    this.speed = -4;
                this.direction = this.speed;
                // create block
                var geometry = new THREE.BoxGeometry(this.dimension.width, this.dimension.height, this.dimension
                    .depth);
                geometry.applyMatrix(new THREE.Matrix4().makeTranslation(this.dimension.width / 2, this
                    .dimension.height / 2, this.dimension.depth / 2));
                this.material = new THREE.MeshToonMaterial({
                    color: this.color,
                    shading: THREE.FlatShading
                });
                this.mesh = new THREE.Mesh(geometry, this.material);
                this.mesh.position.set(this.position.x, this.position.y + (this.state == this.STATES.ACTIVE ?
                    0 : 0), this.position.z);
                if (this.state == this.STATES.ACTIVE) {
                    this.position[this.workingPlane] = Math.random() > 0.5 ? -this.MOVE_AMOUNT : this
                        .MOVE_AMOUNT;
                }
            }
            Block.prototype.reverseDirection = function () {
                this.direction = this.direction > 0 ? this.speed : Math.abs(this.speed);
            };
            Block.prototype.place = function () {
                this.state = this.STATES.STOPPED;
                var overlap = this.targetBlock.dimension[this.workingDimension] - Math.abs(this.position[
                    this.workingPlane] - this.targetBlock.position[this.workingPlane]);
                var blocksToReturn = {
                    plane: this.workingPlane,
                    direction: this.direction
                };
                if (this.dimension[this.workingDimension] - overlap < 0.3) {
                    overlap = this.dimension[this.workingDimension];
                    blocksToReturn.bonus = true;
                    this.position.x = this.targetBlock.position.x;
                    this.position.z = this.targetBlock.position.z;
                    this.dimension.width = this.targetBlock.dimension.width;
                    this.dimension.depth = this.targetBlock.dimension.depth;
                }
                if (overlap > 0) {
                    var choppedDimensions = {
                        width: this.dimension.width,
                        height: this.dimension.height,
                        depth: this.dimension.depth
                    };
                    choppedDimensions[this.workingDimension] -= overlap;
                    this.dimension[this.workingDimension] = overlap;
                    var placedGeometry = new THREE.BoxGeometry(this.dimension.width, this.dimension.height,
                        this.dimension.depth);
                    placedGeometry.applyMatrix(new THREE.Matrix4().makeTranslation(this.dimension.width / 2,
                        this.dimension.height / 2, this.dimension.depth / 2));
                    var placedMesh = new THREE.Mesh(placedGeometry, this.material);
                    var choppedGeometry = new THREE.BoxGeometry(choppedDimensions.width, choppedDimensions
                        .height, choppedDimensions.depth);
                    choppedGeometry.applyMatrix(new THREE.Matrix4().makeTranslation(choppedDimensions
                        .width / 2, choppedDimensions.height / 2, choppedDimensions.depth / 2));
                    var choppedMesh = new THREE.Mesh(choppedGeometry, this.material);
                    var choppedPosition = {
                        x: this.position.x,
                        y: this.position.y,
                        z: this.position.z
                    };
                    if (this.position[this.workingPlane] < this.targetBlock.position[this.workingPlane]) {
                        this.position[this.workingPlane] = this.targetBlock.position[this.workingPlane];
                    } else {
                        choppedPosition[this.workingPlane] += overlap;
                    }
                    placedMesh.position.set(this.position.x, this.position.y, this.position.z);
                    choppedMesh.position.set(choppedPosition.x, choppedPosition.y, choppedPosition.z);
                    blocksToReturn.placed = placedMesh;
                    if (!blocksToReturn.bonus)
                        blocksToReturn.chopped = choppedMesh;
                } else {
                    this.state = this.STATES.MISSED;
                }
                this.dimension[this.workingDimension] = overlap;
                return blocksToReturn;
            };
            Block.prototype.tick = function () {
                if (this.state == this.STATES.ACTIVE) {
                    var value = this.position[this.workingPlane];
                    if (value > this.MOVE_AMOUNT || value < -this.MOVE_AMOUNT)
                        this.reverseDirection();
                    this.position[this.workingPlane] += this.direction;
                    this.mesh.position[this.workingPlane] = this.position[this.workingPlane];
                }
            };
            return Block;
        }());
        var Game = /** @class */ (function () {
            function Game() {
                var _this = this;
                this.STATES = {
                    'LOADING': 'loading',
                    'PLAYING': 'playing',
                    'READY': 'ready',
                    'ENDED': 'ended',
                    'RESETTING': 'resetting'
                };
                this.blocks = [];
                this.state = this.STATES.LOADING;
                this.stage = new Stage();
                this.mainContainer = document.getElementById('container');
                this.scoreContainer = document.getElementById('score');
                this.startButton = document.getElementById('start-button');
                this.instructions = document.getElementById('instructions');
                this.scoreContainer.innerHTML = '0';
                this.newBlocks = new THREE.Group();
                this.placedBlocks = new THREE.Group();
                this.choppedBlocks = new THREE.Group();
                this.stage.add(this.newBlocks);
                this.stage.add(this.placedBlocks);
                this.stage.add(this.choppedBlocks);
                this.addBlock();
                this.tick();
                this.updateState(this.STATES.READY);
                document.addEventListener('keydown', function (e) {
                    if (e.keyCode == 32)
                        _this.onAction();
                });
                document.addEventListener('click', function (e) {
                    _this.onAction();
                });
                document.addEventListener('touchstart', function (e) {
                    e.preventDefault();
                    // this.onAction();
                    // ?? this triggers after click on android so you
                    // insta-lose, will figure it out later.
                });
            }
            Game.prototype.updateState = function (newState) {
                for (var key in this.STATES)
                    this.mainContainer.classList.remove(this.STATES[key]);
                this.mainContainer.classList.add(newState);
                this.state = newState;
            };
            Game.prototype.onAction = function () {
                switch (this.state) {
                    case this.STATES.READY:
                        this.startGame();
                        break;
                    case this.STATES.PLAYING:
                        this.placeBlock();
                        break;
                    case this.STATES.ENDED:
                        this.restartGame();
                        break;
                }
            };
            Game.prototype.startGame = function () {
                if (this.state != this.STATES.PLAYING) {
                    this.scoreContainer.innerHTML = '0';
                    this.updateState(this.STATES.PLAYING);
                    this.addBlock();
                }
            };
            Game.prototype.restartGame = function () {
                var _this = this;
                this.updateState(this.STATES.RESETTING);
                var oldBlocks = this.placedBlocks.children;
                var removeSpeed = 0.2;
                var delayAmount = 0.02;
                var _loop_1 = function (i) {
                    TweenLite.to(oldBlocks[i].scale, removeSpeed, {
                        x: 0,
                        y: 0,
                        z: 0,
                        delay: (oldBlocks.length - i) * delayAmount,
                        ease: Power1.easeIn,
                        onComplete: function () {
                            return _this.placedBlocks.remove(oldBlocks[i]);
                        }
                    });
                    TweenLite.to(oldBlocks[i].rotation, removeSpeed, {
                        y: 0.5,
                        delay: (oldBlocks.length - i) * delayAmount,
                        ease: Power1.easeIn
                    });
                };
                for (var i = 0; i < oldBlocks.length; i++) {
                    _loop_1(i);
                }
                var cameraMoveSpeed = removeSpeed * 2 + (oldBlocks.length * delayAmount);
                this.stage.setCamera(2, cameraMoveSpeed);
                var countdown = {
                    value: this.blocks.length - 1
                };
                TweenLite.to(countdown, cameraMoveSpeed, {
                    value: 0,
                    onUpdate: function () {
                        _this.scoreContainer.innerHTML = String(Math.round(countdown.value));
                    }
                });
                this.blocks = this.blocks.slice(0, 1);
                setTimeout(function () {
                    _this.startGame();
                }, cameraMoveSpeed * 1000);
            };
            Game.prototype.placeBlock = function () {
                var _this = this;
                var currentBlock = this.blocks[this.blocks.length - 1];
                var newBlocks = currentBlock.place();
                this.newBlocks.remove(currentBlock.mesh);
                if (newBlocks.placed)
                    this.placedBlocks.add(newBlocks.placed);
                if (newBlocks.chopped) {
                    this.choppedBlocks.add(newBlocks.chopped);
                    var positionParams = {
                        y: '-=30',
                        ease: Power1.easeIn,
                        onComplete: function () {
                            return _this.choppedBlocks.remove(newBlocks.chopped);
                        }
                    };
                    var rotateRandomness = 10;
                    var rotationParams = {
                        delay: 0.05,
                        x: newBlocks.plane == 'z' ? ((Math.random() * rotateRandomness) - (
                            rotateRandomness / 2)) : 0.1,
                        z: newBlocks.plane == 'x' ? ((Math.random() * rotateRandomness) - (
                            rotateRandomness / 2)) : 0.1,
                        y: Math.random() * 0.1
                    };
                    if (newBlocks.chopped.position[newBlocks.plane] > newBlocks.placed.position[newBlocks
                            .plane]) {
                        positionParams[newBlocks.plane] = '+=' + (40 * Math.abs(newBlocks.direction));
                    } else {
                        positionParams[newBlocks.plane] = '-=' + (40 * Math.abs(newBlocks.direction));
                    }
                    TweenLite.to(newBlocks.chopped.position, 1, positionParams);
                    TweenLite.to(newBlocks.chopped.rotation, 1, rotationParams);
                }
                this.addBlock();
            };
            Game.prototype.addBlock = function () {
                var lastBlock = this.blocks[this.blocks.length - 1];
                if (lastBlock && lastBlock.state == lastBlock.STATES.MISSED) {
                    return this.endGame();
                }
                this.scoreContainer.innerHTML = String(this.blocks.length - 1);
                var newKidOnTheBlock = new Block(lastBlock);
                this.newBlocks.add(newKidOnTheBlock.mesh);
                this.blocks.push(newKidOnTheBlock);
                this.stage.setCamera(this.blocks.length * 2);
                if (this.blocks.length >= 5)
                    this.instructions.classList.add('hide');
            };
            Game.prototype.endGame = function () {
                this.updateState(this.STATES.ENDED);
            };
            Game.prototype.tick = function () {
                var _this = this;
                this.blocks[this.blocks.length - 1].tick();
                this.stage.render();
                requestAnimationFrame(function () {
                    _this.tick();
                });
            };
            return Game;
        }());
        var game = new Game();
    </script>

</body>

</html>